import functools

from models.models import Api, PermissionGroup, Menu, ManagerUser
from rest_framework.serializers import ModelSerializer as MSerializer
from rest_framework import serializers

from water_applets import settings
from django.core.cache import cache


class ModelSerializer(MSerializer):
    """
    ### 自定义要序列化的字段

    """

    def __init__(self, *args, **kwargs):
        fields = kwargs.pop('fields', None)
        exclude = kwargs.pop('exclude', None)
        super(ModelSerializer, self).__init__(*args, **kwargs)
        if fields is not None:
            allowed = set(fields)
            existing = set(self.fields)
            for field in existing - allowed:
                self.fields.pop(field)

        if exclude is not None:
            for field in exclude:
                self.fields.pop(field)

    @staticmethod
    def serialize(cls, obj, **kwargs):
        return cls(instance=obj, **kwargs).data


class ApiSerializer(ModelSerializer):
    class Meta:
        model = Api
        fields = ('id', 'name', 'position', 'method', 'user_default')


class MenuTreeSerializer(ModelSerializer):
    sub_menu = serializers.SerializerMethodField()
    apis = serializers.SerializerMethodField()

    def get_sub_menu(self, obj):
        func = functools.partial(self.serialize, MenuTreeSerializer)
        results = []

        for m in Menu.objects.filter(father=obj):
            results.append(func(m))

        return results

    def get_apis(self, instance):
        return ApiSerializer(Api.objects.filter(menu__id=instance.id), many=True).data

    class Meta:
        model = Menu
        fields = '__all__'


class MenuSerializer(ModelSerializer):

    class Meta:
        model = Menu
        exclude = ('apis',)


class GroupSerializer(ModelSerializer):
    api = serializers.SerializerMethodField()
    menu = serializers.SerializerMethodField()
    type_display = serializers.ReadOnlyField(source='get_type_display')

    def get_api(self, obj):
        func = functools.partial(self.serialize, ApiSerializer)
        results = []
        for api in obj.api.all():
            results.append(func(api))
        return results

    def get_menu(self, obj):
        func = functools.partial(self.serialize, MenuSerializer)
        results = []

        for menu in obj.menu.all():
            results.append(func(menu))
        return results

    class Meta:
        model = PermissionGroup
        fields = '__all__'


class ManagerUserSerializer(ModelSerializer):
    """
    管理员用户序列化
    """
    password = serializers.CharField(write_only=True)
    # permission_group = GroupSerializer(read_only=True)
    # permission_group_id = serializers.IntegerField(write_only=True)
    # permission_group_name = serializers.CharField(source='permission_group.name')
    online = serializers.SerializerMethodField()

    def get_online(self, obj):
        login_user_key = settings.REDIS_MANAGER_LOGIN_TOKEN_KEY.format(user_id=obj.id)
        return cache.get(login_user_key) is not None

    class Meta:
        model = ManagerUser
        fields = '__all__'